#define init_noise
{
/*
    Call this function first. This creates the array with perlin noise, 
    which is used by the functions get_perlin_noise and get_int_perlin_noise.
    
    This function takes two parameters - the width and height of the grid to 
    fill with perlin_noise.
*/
    globalvar noise, noise_falloff, perlin_noise;
    globalvar maxWidth, maxHeight;

    maxWidth = argument[0];
    maxHeight = argument[1];
    
    randomize();
    
    var i, j, k;
    
    //create base noise.
    for(i = 0; i < maxWidth; i += 1)
    {
        for(j = 0; j < maxHeight; j += 1)
        {
            noise[i, j] = random(1);
        }
    }
    
    var smoothnoise, sample_period, amplitude, total_amplitude, octave_count;
    octave_count = 6;
        
    for(i = 0; i < maxWidth; i += 1)
    {
        for(j = 0; j < maxHeight; j += 1)
        {
            smoothnoise = 0;
            sample_period = 64;
            amplitude = 0.5;
            total_amplitude = 0;
            
            for (k = 0; k < octave_count; k += 1)
            {
                total_amplitude += amplitude;
                smoothnoise += get_noise(i, j, sample_period) * amplitude;
                
                sample_period/= 2;
                amplitude /= 2;
            }
            
            
            perlin_noise[i, j] = smoothnoise / total_amplitude;
            //show_debug_message("Perlin noise: " + string(perlin_noise[i, j]));
        }
    }
}
#define get_noise
{
/**
    This function returns smoothnoise. It takes three parameters: 
    the x-coodrinate, the y-coordinate, and the sample_period.
*/
    var x1, y1, z1;
    
    x1 = argument[0];
    y1 = argument[1];
    sample_period = argument[2];
    
    var xx;
    
    xx = floor(x1 / sample_period);
    
    var noiseX1, noiseX2;
    
    noiseX1 = xx * sample_period;
    noiseX2 = (xx + 1) * sample_period;
    
    var yy;
    
    yy = floor(y1 / sample_period);
    
    var noiseY1, noiseY2;
    
    noiseY1 = yy * sample_period;
    noiseY2 = (yy + 1) * sample_period;
    
    var n1, n2, n3, n4;
    
    n1 = noise[noiseX1, noiseY1]; 
    n2 = noise[noiseX1, noiseY2 mod maxHeight]; 
    n3 = noise[noiseX2 mod maxWidth, noiseY1]; 
    n4 = noise[noiseX2 mod maxWidth, noiseY2 mod maxHeight];
		
    var pp, px, py, xy;
    
    pp = sample_period*sample_period;
    px = sample_period*(x1 - noiseX1);
    py = sample_period*(y1 - noiseY1);
    xy = (x1 - noiseX1)*(y1-noiseY1);

    var noiseTmp;
    
    //bilinear interpolation.
    noiseTmp = (pp - px - py + xy) * n1 + (py - xy)*n2 + (px - xy)*n3 + xy*n4;
    
    return noiseTmp / pp;
}
#define get_perlin_noise
{
/**
    This function returns a Perlin noise value at the location (x, y).
    This function takes two parameters - the x-coordinate (an integer) 
    and a y-coordinate (an integer).
*/
    var x1, y1;
    
    x1 = argument0;
    y1 = argument1;
    
    return perlin_noise[x1, y1];
}
#define get_int_perlin_noise
{
/**
    This function returns a perlin_noise value converted to an integer in the range [0, n).
    The function takes three parameters: the x-coordinate, the y-coordinate, and the value n.
*/
    var x1, y1, k, n;
    
    x1 = argument0;
    y1 = argument1;
    k = argument2;
    
    n = get_perlin_noise(x1, y1);
    
    return floor(n * k);
}

#define initialize
// Define the biomes by their order in the game tiles.

#define best_world
var i, j, fits;


fits[0] = world_fitness(0);
//show_debug_message("Got a fit for 1.")
//keyboard_wait();
fits[1] = world_fitness(1);
//show_debug_message("Got a fit for 2.")
//keyboard_wait();
fits[2] = world_fitness(2);
//show_debug_message("Got a fit for 3.")
//keyboard_wait();

var best_fit;
best_fit = min(fits[0], fits[1], fits[2]);
//show_debug_message("Smallest is: " + string(best_fit));

if (best_fit == fits[0])
{
    for (i = 0; i < planetWidth; i += 1)
    {
        for (j = 0; j < planetHeight; j += 1)
        {
            altitude[i, j] = tempAlt0[i, j];
        }
    }
}
else if (best_fit == fits[1])
{
    for (i = 0; i < planetWidth; i += 1)
    {
        for (j = 0; j < planetHeight; j += 1)
        {
            altitude[i, j] = tempAlt1[i, j];
        }
    }
}
else
{
    for (i = 0; i < planetWidth; i += 1)
    {
        for (j = 0; j < planetHeight; j += 1)
        {
            altitude[i, j] = tempAlt2[i, j];
        }
    }
}
#define devise_altitude
//globalvar tempAlt0, tempAlt1, tempAlt2;
   
var n, i, j, k;

for (i = 0; i < planetWidth; i += 1)
{
	for (j = 0; j < planetHeight; j += 1)
	{
		tempAlt0[i, j] = 0;
		tempAlt1[i, j] = 0;
		tempAlt2[i, j] = 0;
	}
}

for (i = 0; i < 3; i += 1)
{
    generate_altitude(i);
}

best_world();
  

#define generate_altitude
init_noise(planetWidth*8, planetHeight*8);
for(i = 0; i < planetWidth; i += 1)
  {
    for(j = 0; j < planetHeight; j += 1)
    {
        n = get_fBm(i, j, 4) //get_fBm(i, j, 5)   

            //show_debug_message("fBm: " + string(n));
            if (n > 3)
            { //will rarely happen
                n = floor(random(4));
               // n = 0;
            }

            //show_debug_message("altitude: " + string(n));
            
            if (argument0 == 0)
            {
                tempAlt0[i, j] = n;
            }
            else if (argument0 == 1)
            {
                tempAlt1[i, j] = n;
            }
            else
            {
                tempAlt2[i, j] = n;
            }
    }
  }
#define generate_biomes
/* Generate the biomes based on a bunch of data to be listed here later. */

var i, j;

for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        if ((altitude[i, j] = 0) or (altitude[i, j] = 3))
        {
            biome[i, j] = BIOME_WATER;
        }
        else if (altitude[i, j] = 2)
        {
            biome[i, j] = BIOME_MTNS;
        }
        else
        {
            if ((j < planetHeight / 8) or (j > (planetHeight - (planetHeight / 8))))
            {
                biome[i, j] = BIOME_TUNDRA;
            }
            else if ((j < planetHeight * (3/8)) or (j > (planetHeight - (planetHeight * (3/8)))))
            {
                // Temperate zone
                if (humidity[i, j] > 0.5)
                {
                    biome[i, j] = BIOME_FOREST;
                }
                else if (humidity[i, j] < 0.2)
                {
                    biome[i, j] = BIOME_DESERT;
                }
                else
                {
                    biome[i, j] = BIOME_PLAINS;
                }
            }
            else if ((j < planetHeight / 2) or (j > planetHeight / 2))
            {
                if (humidity[i, j] < 0.3)
                {
                    biome[i, j] = BIOME_DESERT;
                }
                else if (humidity[i, j] > 0.7)
                {
                    biome[i, j] = BIOME_JUNGLE;
                }
                else
                {
                    biome[i, j] = BIOME_PLAINS;
                }
            }
        }
    }
}
#define generate_humidities
/* Humidity is a decimal between 0 and 1.  Higher altitudes reduce the 
   humidity by 0.3.
   
   Humidity is affected by what region of the planet it's in.  Humidity values
   also need to be dampened -- we don't want a huge change from one space to 
   an adjacent space.
*/

var altReduction, roughHumidity;
altReduction = 0.3;

var i, j;

for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        roughHumidity[i, j] = 0;
    }
}

// This first pass just generates the rough values.
for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        if ((j < planetHeight / 8) or (j > planetHeight - (planetHeight / 8)))
        {
            // For the arctic/antarctic climates, generate a random 
            // number between 0.0 to 0.6.
            roughHumidity[i, j] = random(0.6);
            
        }
        else if ((j < planetHeight / 4) or (j > planetHeight - (planetHeight / 4)))
        {
            // For the temperate climates, generate a random number 
            // between 0.1 and 0.7.
            roughHumidity[i, j] = random(0.6) + 0.1;
        }
        else if ((j < planetHeight / 2) or (j > planetHeight / 2))
        {
            // For the equatorial region, generate a random number 
            // between 0.0 and 1.0
            roughHumidity[i, j] = random(1.0);
        }
        
        if (altitude[i, j] > 1)
        {
            roughHumidity[i, j] -= altReduction;
            //if (roughHumidity[i, j] < 0)
            //{
            //    roughHumidity[i, j] = 0.0;
            //}
        }
    }
}

// The second pass dampens out the values by doing a weighted sum of the
// values around it.
var sumAround;
for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        sumAround = 0;
        if (j = 0)
        {
            // Top of the world!  Don't look up!
            sumAround = 0.167 * roughHumidity[((i + planetWidth + 1) mod planetWidth), j];
            sumAround += 0.167 * roughHumidity[(i + 1) mod planetWidth, j];
            sumAround += 0.167 * roughHumidity[((i + planetWidth + 1) mod planetWidth), j + 1];
            sumAround += 0.167 * roughHumidity[i, j + 1];
            sumAround += 0.167 * roughHumidity[(i + 1) mod planetWidth, j + 1];
            sumAround += 0.333 * roughHumidity[i, j];
            humidity[i, j] = sumAround;
        }
        
        else if (j < planetHeight - 1)
        {
            // The big mid-region of the world.  Look all around.
            sumAround = 0.1 * roughHumidity[((i + planetWidth + 1) mod planetWidth), (j - 1)];
            sumAround += 0.1 * roughHumidity[i, (j - 1)];
            sumAround += 0.1 * roughHumidity[(i + 1) mod planetWidth, (j - 1)]
            sumAround += 0.1 * roughHumidity[(i + planetWidth + 1) mod planetWidth, j];
            sumAround += 0.1 * roughHumidity[(i + 1) mod planetWidth, j];
            sumAround += 0.1 * roughHumidity[(i + planetWidth + 1) mod planetWidth, j + 1];
            sumAround += 0.1 * roughHumidity[i, j + 1];
            sumAround += 0.1 * roughHumidity[(i + 1) mod planetWidth, j + 1];
            sumAround += 0.2 * roughHumidity[i, j];
            humidity[i, j] = sumAround;
        }
        else
        {
            // The bottom of the world!  Don't look down!
            sumAround = 0.167 * roughHumidity[(i + planetWidth + 1) mod planetWidth, (j - 1)];
            sumAround += 0.167 * roughHumidity[i, (j - 1)];
            sumAround += 0.167 * roughHumidity[(i + 1) mod planetWidth, (j - 1)]
            sumAround += 0.167 * roughHumidity[(i + planetWidth + 1) mod planetWidth, j];
            sumAround += 0.167 * roughHumidity[(i + 1) mod planetWidth, j];
            sumAround += 0.333 * roughHumidity[i, j];
            humidity[i, j] = sumAround;
        }
    }
}
#define generate_temperatures
/* Generate temperatures for the places in the three regions of Namatjira: 
    Arctic, Temperate, and Equatorial.
    
    Altitude lowers the temperature in a space by 7 to 12 C.
*/

var i, j;

for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        if ((j < planetHeight / 8) or (j > planetHeight - (planetHeight / 8)))
        {
            // For the arctic/antarctic climates, generate a random 
            // number between -75 and 0 C.
            temperature[i, j] = -floor(random(76));
            
        }
        else if ((j < planetHeight * (3/8)) or (j > planetHeight - (planetHeight * (3/8))))
        {
            // For the temperate climates, generate a random number 
            // between -5 and 30 C.
            temperature[i, j] = floor(random(36)) - 5;
        }
        else if ((j < planetHeight / 2) or (j > planetHeight / 2))
        {
            // For the equatorial region, generate a random number 
            // between 27 and 50 C.
            temperature[i, j] = floor(random(25)) + 27;
        }
        
        if (altitude[i, j] > 1)
        {
            temperature[i, j] = temperature[i, j] - (floor(random(6)) + 7);
        }
    }
}
#define world_fitness
var totalSpaces;
var waterCount;

totalSpaces = 0;
waterCount = 0;

totalSpaces = planetHeight * planetWidth;

var i, j;
for (i = 0; i < planetWidth; i += 1)
{
	for (j = 0; j < planetHeight; j += 1)
	{
            //show_debug_message("checking for water: " + string(tempAlt0[i, j]));
            //keyboard_wait();
            if (argument0 == 0)
            {
                if ((tempAlt0[i, j] == 0) or (tempAlt0[i, j] == 3))
                {
                    waterCount += 1;
                }
            }
            else if (argument0 == 1)
            {
                if ((tempAlt1[i, j] == 0) or (tempAlt1[i, j] == 3))
                {
                    waterCount += 1;
                }
            }
            else
            {
                if ((tempAlt2[i, j] == 0) or (tempAlt2[i, j] == 3))
                {
                    waterCount += 1;
                }
            }
	}
}

//show_debug_message("Fit: " + string(abs(0.5 - (waterCount / totalSpaces))));
//keyboard_wait();
return abs(0.5 - (waterCount / totalSpaces));
#define generate_planet
/* Created by Lissa Avery
    March 2, 2008
    
    The planet generation is done through the use of a Perlin noise 
    generator and fractal Brownian motion (fBm).  Code borrowed heavily from 
    Gamasutra's guide to procedurally-generating planetary bodies @ 
    http://www.gamasutra.com/features/20010302/oneil_02.htm.
*/

{

    // The entire planet.  Note that we only need half the number of spaces as 
    // there are given by the resolution, courtesty of the method used for 
    // interpolating the boundaries between regions.
    
    /* Each location on Namatjira will have the following pieces of information:

    0: Altitude (generated with Perlin noise, from 0 to 2)
    1: Temperature (Celsius)
    2: Humitidy (float from 0 to 1)
    3: Civilization density (float from 0 to 1)
    4: Biome (0 - 3)
    */  
    globalvar biome, altitude, temperature, humidity, civDensity, randSeed;
    globalvar planetWidth, planetHeight;
    var i, j;
    
    planetWidth = room_width / 64;
    planetHeight = room_height / 64;
    for (i = 0; i < planetWidth; i += 1)
    {
        for (j = 0; j < planetHeight; j += 1)
        {
            biome[i, j] = 0;
            altitude[i, j] = 0;
            temperature[i, j] = 0;
            humidity[i, j] = 0;
            civDensity[i, j] = 0;
        }
    }
    randomize();
    
    init_tileset_refs();
    devise_altitude();
    //keyboard_wait();
    generate_temperatures();
    generate_humidities();
    generate_biomes();
    
    render_biomes();
}
#define init_tileset_refs
bgComboMap = ds_map_create();
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_PLAINS), bgWaterPlains);
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_TUNDRA), bgWaterTundra);
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_DESERT), bgWaterDesert);
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_FOREST), bgWaterForest);
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_JUNGLE), bgWaterJungle);
ds_map_add(bgComboMap, string(BIOME_WATER) + string(BIOME_MTNS), bgWaterMtns);

ds_map_add(bgComboMap, string(BIOME_PLAINS) + string(BIOME_FOREST), bgPlainsForest);
ds_map_add(bgComboMap, string(BIOME_PLAINS) + string(BIOME_DESERT), bgPlainsDesert);
ds_map_add(bgComboMap, string(BIOME_PLAINS) + string(BIOME_JUNGLE), bgPlainsJungle);
ds_map_add(bgComboMap, string(BIOME_PLAINS) + string(BIOME_MTNS), bgPlainsMtns);
ds_map_add(bgComboMap, string(BIOME_PLAINS) + string(BIOME_TUNDRA), bgPlainsTundra);

ds_map_add(bgComboMap, string(BIOME_TUNDRA) + string(BIOME_FOREST), bgTundraForest);
ds_map_add(bgComboMap, string(BIOME_TUNDRA) + string(BIOME_MTNS), bgTundraMtns);
ds_map_add(bgComboMap, string(BIOME_TUNDRA) + string(BIOME_DESERT), bgTundraDesert);

ds_map_add(bgComboMap, string(BIOME_DESERT) + string(BIOME_FOREST), bgDesertForest);
ds_map_add(bgComboMap, string(BIOME_DESERT) + string(BIOME_JUNGLE), bgDesertJungle);
ds_map_add(bgComboMap, string(BIOME_DESERT) + string(BIOME_MTNS), bgDesertMtns);

ds_map_add(bgComboMap, string(BIOME_FOREST) + string(BIOME_JUNGLE), bgForestJungle);
ds_map_add(bgComboMap, string(BIOME_FOREST) + string(BIOME_MTNS), bgForestMtns);

ds_map_add(bgComboMap, string(BIOME_JUNGLE) + string(BIOME_MTNS), bgJungleMtns);

ds_map_add(bgComboMap, string(BIOME_PLAINS) + "T", bgTransPlains);
ds_map_add(bgComboMap, string(BIOME_FOREST) + "T", bgTransForest);
ds_map_add(bgComboMap, string(BIOME_TUNDRA) + "T", bgTransTundra);
ds_map_add(bgComboMap, string(BIOME_DESERT) + "T", bgTransDesert);
ds_map_add(bgComboMap, string(BIOME_JUNGLE) + "T", bgTransJungle);
ds_map_add(bgComboMap, string(BIOME_MTNS) + "T", bgTransMtns);
#define render_biomes

initial_tile_render();
horizontal_interpolation();
vertical_interpolation();
diagonal_interpolation();
#define initial_tile_render
var i, j;

// Show the first set of tiles by simply using the appropriate tile 
// from the bgWorldTiles set that matches the biome.
for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        tile_set_visible(tile_add(bgWorldTiles, floor(random(3))*32, biome[i, j]*32, 32, 32, i*64, j*64, 10000), true);
    }
}
#define horizontal_interpolation
var i, j;

for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight; j += 1)
    {
        if ((biome[i, j] == biome[((i + planetWidth + 1) mod planetWidth), j]))
        {
            // Then I want the same tile betwixt the two.
            tile_set_visible(tile_add(bgWorldTiles, floor(random(3))*32, biome[i, j]*32, 32, 32, i*64+32, j*64, 10000), true);
        }

        // Check the biome here and at the space to the right.
        // If it's a plains/forest bridge, find out which direction.
        else if (biome[i, j] < biome[((i + planetWidth + 1) mod planetWidth), j])
        {
            // Then I want a plains/forest tile betwixt the two.
            tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[i, j]) + string(biome[((i + planetWidth + 1) mod planetWidth), j])), 0, 32, 32, 32, i*64+32, j*64, 10000), true);
        }
        else 
        {
            // Then I want a plains/forest tile betwixt the two.
            tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[((i + planetWidth + 1) mod planetWidth), j]) + string(biome[i, j])), 32, 32, 32, 32, i*64+32, j*64, 10000), true);
        }
     }
}
#define vertical_interpolation
var i, j;

for (j = 0; j < planetHeight - 1; j += 1)
{
    for (i = 0; i < planetWidth; i += 1)
    {
        if ((biome[i, j] == biome[i, j + 1]))
        {
            // Then I want the same tile betwixt the two.
            tile_set_visible(tile_add(bgWorldTiles, floor(random(3))*32, biome[i, j]*32, 32, 32, i*64, j*64+32, 10000), true);
        }

        // Check the biome here and at the space to the right.
        // If it's a plains/forest bridge, find out which direction.
        else if (biome[i, j] < biome[i, j + 1])
        {
            //show_error(string(biome[i, j]) + string(biome[i, j + 1]), false);
            tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[i, j]) + 
                string(biome[i, j + 1])), 
                3*32, 2*32, 32, 32, i*64, j*64+32, 10000), true);
        }
        else 
        {
            //show_debug_message(string(biome[i, j + 1]) + string(biome[i, j]));
            tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[i, j + 1]) + 
                string(biome[i, j])), 
                2*32, 2*32, 32, 32, i*64, j*64+32, 10000), true);
        }
    }
}
#define diagonal_interpolation
var i, j;

for (i = 0; i < planetWidth; i += 1)
{
    for (j = 0; j < planetHeight - 1; j += 1)
    {
        if (is_four_same_biomes(i, j))
        {
            // Then I want the same tile betwixt the four.
            tile_set_visible(tile_add(bgWorldTiles, floor(random(3))*32, biome[i, j]*32, 32, 32, i*64+32, j*64+32, 10000), true);
        }
        else if (is_left_uniform_right_uniform(i, j))
        {
            render_left_right(i, j, j);        
        }
        else if (is_top_uniform_bottom_uniform(i, j))
        {
            render_top_bottom(i, j);
        }
        else if (is_upper_left_uniform(i, j))
        {
            render_upper_left_uniform(i, j);
        }
        else if (is_upper_right_uniform(i, j))
        {
            render_upper_right_uniform(i, j);
        }
        else if (is_lower_left_uniform(i, j))
        {
            render_lower_left_uniform(i, j);
        }
        else if (is_lower_right_uniform(i, j))
        {
            render_lower_right_uniform(i, j);
        }
        else if (is_left_uniform(i, j))
        {
            render_left_uniform(i, j);
        }
        else if (is_right_uniform(i, j))
        {
            //render_right_uniform(i, j);
        }
        else if (are_left_catty_corners_uniform(i, j))
        {
            //render_left_catty_corners_uniform(i, j);
        }
    }
}    
#define is_four_same_biomes
if ((biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
    and (biome[argument0, argument1] == biome[argument0, argument1 + 1]) 
    and (biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define is_left_uniform
if (biome[argument0, argument1] == biome[argument0, argument1 + 1]) 
{
    return true;
}

return false;
#define is_left_uniform_right_uniform
if ((biome[argument0, argument1] == biome[argument0, argument1 + 1]) 
    and (biome[(1 + argument0 + planetWidth) mod planetWidth, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define is_lower_left_uniform
if ((biome[argument0, argument1] == biome[argument0, argument1 + 1]) 
    and (biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define is_lower_right_uniform
if ((biome[argument0, argument1 + 1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
    and (biome[argument0, argument1 + 1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define is_right_uniform
if (biome[(1 + argument0 + planetWidth) mod planetWidth, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]) 
{
    return true;
}

return false;
#define is_top_uniform_bottom_uniform
if ((biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
    and (biome[argument0, argument1 + 1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define is_upper_left_uniform
if ((biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
    and (biome[argument0, argument1] == biome[argument0, argument1 + 1]))
{
    return true;
}

return false;
#define is_upper_right_uniform
if ((biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
    and (biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]))
{
    return true;
}

return false;
#define render_left_right
// Check the biome here and at the space to the right.
        // If it's a plains/forest bridge, find out which direction.
        if (biome[argument0, argument1] < biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])
        {
            //show_error(string(biome[argument0, argument1]) + string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1]), false);
            // Then I want a plains/forest tile betwixt the two.
            tile_set_visible(tile_add(
                ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])), 
                0, 32, 32, 32, argument0*64+32, argument2*64+32, 10000), true);
        }
        else 
        {
            // Then I want a plains/forest tile betwixt the two.
            tile_set_visible(tile_add(
                ds_map_find_value(bgComboMap, string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1]) + 
                string(biome[argument0, argument1])), 
                32, 32, 32, 32, argument0*64+32, argument2*64+32, 10000), true);
        }
        
#define render_left_uniform
// First, see which of the two non-uniform tiles has the lowest index.
if (biome[(argument0 + planetWidth + 1) mod planetWidth, argument1] < biome[(argument0 + planetWidth + 1) mod planetWidth, argument1 + 1])
{
    // Since it's the top one, use that to lay down a half-half 
    // tile of the left and top right one.   
    render_left_right(argument0, argument1, argument1);
    //render_transparent_lower_right((argument0 + planetWidth + 1) mod planetWidth, argument1 + 1, argument0, argument1);
}
else
{
    render_left_right(argument0, argument1 + 1, argument1);
    //render_transparent_upper_right((argument0 + planetWidth + 1) mod planetWidth, argument1, argument0, argument1);
}
#define render_left_catty_corners_uniform
// First, see which of the two non-uniform tiles has the lowest index.
if (biome[(argument0 + planetWidth + 1) mod planetWidth, argument1] < biome[argument0, argument1 + 1])
{
    // Since it's the top one, use that to lay down a half-half 
    // tile of the left and top right one.   
    render_lower_right_uniform(argument0, argument1);
    render_transparent_lower_right((argument0 + planetWidth + 1) mod planetWidth, argument1 + 1, argument0, argument1);
}
else
{
    render_lower_left_uniform(argument0, argument1);
    render_transparent_upper_right((argument0 + planetWidth + 1) mod planetWidth, argument1, argument0, argument1);
}
#define render_right_catty_corners_uniform
// First, see which of the two non-uniform tiles has the lowest index.
if (biome[argument0, argument1] < biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1])
{
    // Since it's the top one, use that to lay down a half-half 
    // tile of the left and top right one.   
    render_lower_right_uniform(argument0, argument1);
    render_transparent_lower_right((argument0 + planetWidth + 1) mod planetWidth, argument1 + 1, argument0, argument1);
}
else
{
    render_lower_left_uniform(argument0, argument1);
    render_transparent_upper_right((argument0 + planetWidth + 1) mod planetWidth, argument1, argument0, argument1);
}
#define render_lower_left_uniform
if (biome[argument0, argument1]< biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])),
                0, 2*32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
else 
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1]) + 
                string(biome[argument0, argument1])),
                2*32, 32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}

#define render_lower_right_uniform
if (biome[argument0, argument1]< biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1])),
                32, 3*32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
else 
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1]) + 
                string(biome[argument0, argument1])),
                32, 2*32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
#define render_right_uniform
// First, see which of the two non-uniform tiles has the lowest index.
if (biome[argument0, argument1] < biome[argument0, argument1 + 1])
{
    // Since it's the top one, use that to lay down a half-half 
    // tile of the left and top right one.   
    //render_left_right(argument0, argument1, argument1);
    render_transparent_lower_left(argument0, argument1 + 1, argument0, argument1);
}
else
{
    render_left_right(argument0, argument1 + 1, argument1);
    render_transparent_upper_left(argument0, argument1, argument0, argument1);
}
#define render_top_bottom
if (biome[argument0, argument1]< biome[argument0, argument1 + 1])
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[argument0, argument1 + 1])),
                3*32, 2*32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
else 
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1 + 1]) + 
                string(biome[argument0, argument1])),
                2*32, 2*32, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
#define render_transparent_lower_left
tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                "T"), 32, 0, 32, 32, argument2*64+32, argument3*64+32, 1000), true);
#define render_transparent_lower_right
tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                "T"), 0, 0, 32, 32, argument2*64+32, argument3*64+32, 1000), true);

#define render_transparent_upper_left
tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                "T"), 32, 2*32, 32, 32, argument2*64+32, argument3*64+32, 1000), true);

#define render_transparent_upper_right
tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                "T"), 0, 2*32, 32, 32, argument2*64+32, argument3*64+32, 1000), true);

#define render_upper_left_uniform
if (biome[argument0, argument1]< biome[((argument0 + planetWidth + 1) mod planetWidth), argument1 + 1])
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1 + 1])),
                0, 0, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
else 
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, 
                string(biome[((argument0 + planetWidth + 1) mod planetWidth), argument1 + 1]) + 
                string(biome[argument0, argument1])),
                2*32, 0, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
#define render_upper_right_uniform
if (biome[argument0, argument1]< biome[argument0, argument1 + 1])
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1]) + 
                string(biome[argument0, argument1 + 1])),
                32, 0, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}
else 
{
    tile_set_visible(tile_add(ds_map_find_value(bgComboMap, string(biome[argument0, argument1 + 1]) + 
                string(biome[argument0, argument1])),
                3*32, 0, 32, 32, argument0*64+32, argument1*64+32, 10000), true);
}

#define are_left_catty_corners_uniform
if (biome[argument0, argument1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1 + 1]) 
{
    if (are_right_catty_corners_uniform(argument0, argument1) and (biome[argument0, argument1] > biome[argument0, argument1 + 1]))
    {
        // It's better that it use the right-catty-corner method of rendering.
        return false;
    }
    return true;
}

return false;
#define are_right_catty_corners_uniform
if (biome[argument0, argument1 + 1] == biome[(1 + argument0 + planetWidth) mod planetWidth, argument1]) 
{
    return true;
}

return false;
#define get_fBm
// argument0: x coord
// argument1: y coord
// argument2: octaves

globalvar fValue;
fValue = 0.0;
globalvar fWeight;
fWeight = 1.0;
var i, j;

globalvar fTemp;
fTemp[0] = argument0;
fTemp[1] = argument1;

for(i=0; i < argument2; i += 1)
{
    fValue += get_int_perlin_noise(fTemp[0], fTemp[1], 4) * fWeight; // Sum weighted noise value
    //show_debug_message("P-noise at (" + string(fTemp[0]) + ", " + string(fTemp[1]) + "): " + string(get_int_perlin_noise(fTemp[0], fTemp[1], 50)));
    fWeight *= 0.75; // Adjust the weight
    for(j=0; j < 2; j += 1)
    {
       fTemp[j] *= 2.0;
    }
}

return fValue;
